/************************************************************************************
 *                                                                                  *
 *                                                                                  *
 ************************************************************************************/
package jMiiEditor.mii;

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import utils.BinStuffs;

/**
 * @author CC
 * TODO: use JAXB2.0 (XmlAttachmentRef?, XmlAttribute!, XmlElement!)
 */
public class MiiXML {

    public static class toXMLAttribut {
        boolean     appendMyAvatarEditorDotComHeader;
        boolean     appendMyAvatarEditorDotComXMLNS;
        String      tab;
        String      eol;

        public toXMLAttribut(
                final boolean   appendMyAvatarEditorDotComHeader,
                final boolean   appendMyAvatarEditorDotComXMLNS,
                final String    tab,
                final String    eol
                )
        {
            this.appendMyAvatarEditorDotComHeader = appendMyAvatarEditorDotComHeader;
            this.appendMyAvatarEditorDotComXMLNS = appendMyAvatarEditorDotComXMLNS;
            this.tab = tab;
            this.eol = eol;
        }

        public toXMLAttribut(
                final boolean   appendMyAvatarEditorDotComHeader,
                final boolean   appendMyAvatarEditorDotComXMLNS
                )
        {
            this( appendMyAvatarEditorDotComHeader, appendMyAvatarEditorDotComXMLNS, "  ", "\n" );
        }

        public toXMLAttribut()
        {
            this( true, true, "  ", "\n" );
        }
    }

    private static class toXMLAppender {
        private Appendable a;
        private toXMLAttribut attribut;

        public toXMLAppender( final Appendable a, final toXMLAttribut attribut )
        {
            this.a = a;
            this.attribut = attribut;
        }

        public void appendLine( final int tabCount, final String s ) throws IOException
        {
            for( int i = 0; i<tabCount; i++ ) {
                this.a.append( attribut.tab );
            }
            a.append( s );
            a.append( attribut.eol );
        }

        public void appendLine( final String s ) throws IOException
        {
            appendLine( 0, s );
        }

        public void append(
                final String    elementName,
                final int       tabCount,
                final String    s
                ) throws IOException
            {
                appendLine( tabCount, "<" + elementName + ">" + s.trim() + "</" + elementName + ">" );
            }

        public void append(
                final String    elementName,
                final int       tabCount,
                final byte[]    bytes
                ) throws IOException
            {
                append( elementName, tabCount, BinStuffs.toHexString( bytes ) );
            }

        public void append(
                final String    elementName,
                final int       tabCount,
                final boolean   bool
                ) throws IOException
            {
                append( elementName, tabCount, BinStuffs.toIntegerString( bool ) );
            }

        public void append(
                final String    elementName,
                final int       tabCount,
                final int       intValue
                ) throws IOException
            {
                append( elementName, tabCount, Integer.toString( intValue ) );
            }
    }

    public static final void toXML( final Appendable a, final Mii mii, final toXMLAttribut attribut ) throws IOException
    {
        final toXMLAppender appender = new toXMLAppender( a, attribut );

        if( attribut.appendMyAvatarEditorDotComHeader ) {
            appender.appendLine( "<?xml version=\"1.0\" ?>" );
            appender.appendLine( "<?xml-stylesheet type=\"text/xsl\" href=\"/xml/avatar.xsl\" ?>" );
            appender.appendLine( "<!DOCTYPE avatar-collection SYSTEM \"/xml/avatar.dtd\" >" );
        }

        if( attribut.appendMyAvatarEditorDotComXMLNS ) {
            appender.appendLine( "<Avatar xmlns=\"http://www.myavatareditor.com/xml/avatar/1\">" );
        }
        else {
            appender.appendLine( "<Avatar>" );
        }

        appender.append( "id", 1, mii.getMiiId() );
        appender.append( "clientID", 1, mii.getSystemId() );
        appender.append( "name", 1, mii.getMiiName() );
        appender.append( "creatorName", 1, mii.getMiiCreator() );
        appender.append( "birthDay", 1, mii.getDay() );
        appender.append( "birthMonth", 1, mii.getMonth() );
        appender.append( "gender", 1,  mii.isGirl() );
        appender.append( "mingles", 1,  mii.isMingleOff() );

        appender.appendLine( 1, "<Beard>" );
        appender.append( "type", 2,  mii.getBeardType() );
        appender.append( "color", 2,  mii.getFacialHairColor() );
        appender.appendLine( 1, "</Beard>" );

        appender.appendLine( 1, "<Body>" );
        appender.append( "height", 2, mii.getHeight() );
        appender.append( "weight", 2, mii.getWeight() );
        appender.appendLine( 1, "</Body>" );

        appender.appendLine( 1, "<Eye>" );
        appender.append( "type", 2,  mii.getEyeType() );
        appender.append( "color", 2,  mii.getEyeColor() );
        appender.append( "x", 2,  mii.getEyeHorizSpacing() );
        appender.append( "y", 2,  mii.getEyeVertPos() );
        appender.append( "size", 2,  mii.getEyeSize() );
        appender.append( "rotation", 2,  mii.getEyeRotation() );
        appender.appendLine( 1, "</Eye>" );

        appender.appendLine( 1, "<Eyebrow>" );
        appender.append( "type", 2,  mii.getEyebrowType() );
        appender.append( "color", 2,  mii.getEyebrowColor() );
        appender.append( "x", 2,  mii.getEyebrowHorizSpacing() );
        appender.append( "y", 2,  mii.getEyebrowVertPos() );
        appender.append( "size", 2,  mii.getEyebrowSize() );
        appender.append( "rotation", 2,  mii.getEyebrowRotation() );
        appender.appendLine( 1, "</Eyebrow>" );

        appender.appendLine( 1, "<Face>" );
        appender.append( "type", 2,  9 );  // $$$ 1001
        appender.appendLine( 1, "</Face>" );

        appender.appendLine( 1, "<Glasses>" );
        appender.append( "type", 2,  mii.getGlassesType() );
        appender.append( "color", 2,  mii.getGlassesColor() );
        appender.append( "y", 2,  mii.getGlassesVertPos() );
        appender.append( "size", 2,  mii.getGlassesSize() );
        appender.appendLine( 1, "</Glasses>" );

        appender.appendLine( 1, "<Hair>" );
        appender.append( "type", 2,  mii.getHairType() );
        appender.append( "color", 2,  mii.getHairColor() );
        appender.append( "part", 2,  mii.isHairPartReversed() );
        appender.appendLine( 1, "</Hair>" );

        appender.appendLine( 1, "<Head>" );
        appender.append( "type", 2,  mii.getFaceShape() );
        appender.appendLine( 1, "</Head>" );

        appender.appendLine( 1, "<Mole>" );
        appender.append( "type", 2, mii.isMoleOn() );
        appender.append( "x", 2,  mii.getMoleHorizPos() );
        appender.append( "y", 2,  mii.getMoleVertPos() );
        appender.append( "size", 2,  mii.getMoleSize() );
        appender.appendLine( 1, "</Mole>" );

        appender.appendLine( 1, "<Mouth>" );
        appender.append( "type", 2,  mii.getLipType() );
        appender.append( "color", 2,  mii.getLipColor() );
        appender.append( "y", 2,  mii.getLipVertPos() );
        appender.append( "size", 2,  mii.getLipSize() );
        appender.appendLine( 1, "</Mouth>" );

        appender.appendLine( 1, "<Mustache>" );
        appender.append( "type", 2,  mii.getMustacheType() );
        appender.append( "y", 2,  mii.getMustacheVertPos() );
        appender.append( "size", 2,  mii.getMustacheSize() );
        appender.appendLine( 1, "</Mustache>" );

        appender.appendLine( 1, "<Nose>" );
        appender.append( "type", 2,  mii.getNoseType() );
        appender.append( "y", 2,  mii.getNoseVertPos() );
        appender.append( "size", 2,  mii.getNoseSize() );
        appender.appendLine( 1, "</Nose>" );

        appender.appendLine( 1, "<Shirt>" );
        appender.append( "color", 2,  0 );  // $$$
        appender.appendLine( 1, "</Shirt>" );

        appender.appendLine( 1, "<Skin>" );
        appender.append( "color", 2,  mii.getSkinColor() );
        appender.appendLine( 1, "</Skin>" );

        appender.appendLine( "</Avatar>" );
    }

    public static final String toXML( final Mii mii, final toXMLAttribut attribut )
    {
        final StringBuilder sb = new StringBuilder();

        try {
            toXML( sb, mii, attribut );
        } catch (IOException e) {
            throw  new RuntimeException( e ); // should not occur
        }

        return sb.toString();
    }

    public static final void toXML(
            final String            filename,
            final Mii       mii,
            final toXMLAttribut     attribut
            ) throws IOException
    {
        final Writer writer = new FileWriter( filename );

        toXML( writer, mii, attribut );

        writer.close();
    }
}
